home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / xview / segal / mask_grow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-25  |  17.8 KB  |  787 lines

  1. /*
  2.  *    mask_grow.c - For use with SEGAL
  3.  *
  4.  *    Bryan Skene, LBL July 1991
  5.  *    Rewritten for SEGAL 3d: 7/92
  6.  */
  7.  
  8. #include "common.h"
  9.  
  10. static int dx[NUM_DIRECTIONS] = {
  11.     0, 0, -1, 1, 0, 0
  12.     };
  13.  
  14. static int dy[NUM_DIRECTIONS] = {
  15.     -1, 1, 0, 0, 0, 0
  16.     };
  17.  
  18. static int df[NUM_DIRECTIONS] = {
  19.     0, 0, 0, 0, 1, -1
  20.     };
  21.  
  22. static int xoff_ns[8] = {
  23.     0, 1, 1, 1, 0, -1, -1, -1
  24.     };
  25.  
  26. static int xoff_ew[8] = {
  27.     0, 0, 0, 0, 0, 0, 0, 0
  28.     };
  29.  
  30. static int xoff_ud[8] = {
  31.     0, 1, 1, 1, 0, -1, -1, -1
  32.     };
  33.  
  34. static int yoff_ns[8] = {
  35.     0, 0, 0, 0, 0, 0, 0, 0
  36.     };
  37.  
  38. static int yoff_ew[8] = {
  39.     0, -1, -1, -1, 0, 1, 1, 1
  40.     };
  41.  
  42. static int yoff_ud[8] = {
  43.     -1, -1, 0, 1, 1, 1, 0, -1
  44.     };
  45.  
  46. static int foff_ns[8] = {
  47.     -1, -1, 0, 1, 1, 1, 0, -1
  48.     };
  49.  
  50. static int foff_ew[8] = {
  51.     -1, -1, 0, 1, 1, 1, 0, -1
  52.     };
  53.  
  54. static int foff_ud[8] = {
  55.     0, 0, 0, 0, 0, 0, 0, 0
  56.     };
  57.  
  58. static STACK_INFO stack[NUM_BRIDGE_DIRS];
  59. static LOGIC connected[NUM_BRIDGE_DIRS];
  60.  
  61. /**********************************************/
  62. void
  63. grow_mask()
  64. {
  65.     void set_region();
  66.     void map_buffers();
  67.     int max_frames();
  68.     void grow_frame();
  69.     void set_frame_slider();
  70.  
  71.     int i;
  72.  
  73.     /* Things to be done at the beginning of any growth */
  74.     For_all_bridge_strengths {
  75.         if(stack[i].pts != NULL) free(stack[i].pts);
  76.  
  77.         stack[i].max_pts = NUM_PTS_PER_ALLOC; 
  78.         stack[i].num_pts_per_alloc = NUM_PTS_PER_ALLOC;
  79.         stack[i].pts = (POINT_TYPE *) calloc(stack[i].max_pts, sizeof(POINT_TYPE));
  80.         stack[i].num_pts = 0;
  81.     }
  82.  
  83.     switch(grow.extent) {
  84.     case GROW_FRAME :
  85.         set_region(win[grow.swin].aspect, 0, 0, win[grow.swin].f,
  86.             win[grow.swin].img_c - 1, win[grow.swin].img_r - 1,
  87.             win[grow.swin].f);
  88.         grow_frame();
  89.         break;
  90.  
  91.     case GROW_BEG_TO_END :
  92.         /* setup interrupt growth parameters */
  93.         win[grow.swin].f = region.beg_frame;
  94.         win[grow.swin].repaint = TRUE;
  95.         map_buffers();
  96.  
  97.         if(region.beg_frame <= region.end_frame) {
  98.             frame.upper = region.end_frame;
  99.             frame.lower = region.beg_frame;
  100.         }
  101.         else {
  102.             frame.upper = region.beg_frame;
  103.             frame.lower = region.end_frame;
  104.         }
  105.         set_region(win[grow.swin].aspect, 0, 0, frame.lower,
  106.             win[grow.swin].img_c - 1, win[grow.swin].img_r - 1,
  107.             frame.upper);
  108.         grow_frame();
  109.         break;
  110.  
  111.     case GROW_ALL :
  112.         set_region(win[grow.swin].aspect, 0, 0, 0,
  113.             win[grow.swin].img_c - 1, win[grow.swin].img_r - 1,
  114.             max_frames(win[grow.swin].aspect));
  115.         grow_frame();
  116.         break;
  117.  
  118.     default :
  119.     break;
  120.     }
  121. }
  122.  
  123. /**********************************************/
  124. void
  125. done_growing_mask()
  126. {
  127.     void redisplay_all();
  128.  
  129.     int i, p;
  130.  
  131.     For_all_bridge_strengths {
  132.         vprint"freeing stack[%d] (size = %u, points = %u)\n", i,
  133.             (p = pointer_buffer_size(stack[i].pts)), p / 6);
  134.         free(stack[i].pts);
  135.         stack[i].pts = NULL;
  136.     }
  137.  
  138.     xv_set(Mask_grow_pop_mask_grow->but_stop,
  139.         PANEL_INACTIVE, TRUE,
  140.         NULL);
  141.          
  142.     xv_set(Mask_grow_pop_mask_grow->but_continue,
  143.         PANEL_INACTIVE, TRUE,
  144.         NULL);
  145.  
  146.     if(grow.extent == GROW_BEG_TO_END) {
  147.         win[grow.swin].f = region.end_frame;
  148.         set_frame_slider(grow.swin);
  149.     }
  150.  
  151.     redisplay_all();
  152. }
  153.  
  154. /**********************************************/
  155. void
  156. set_region(asp_id, x1, y1, f1, x2, y2, f2)
  157. int asp_id, x1, y1, f1, x2, y2, f2;
  158. {
  159.     void get_3d_coords();
  160.     void organize_region();
  161.  
  162.     get_3d_coords(asp_id, ASPECT_Z, x1, y1, f1,
  163.         ®ion.x1, ®ion.y1, ®ion.f1);
  164.     get_3d_coords(asp_id, ASPECT_Z, x2, y2, f2,
  165.         ®ion.x2, ®ion.y2, ®ion.f2);
  166.  
  167.     organize_region();
  168. }
  169.  
  170. /**********************************************/
  171. void
  172. organize_region()
  173. {
  174.     void swap();
  175.  
  176.     if(region.x1 > region.x2) swap(®ion.x1, ®ion.x2);
  177.     if(region.y1 > region.y2) swap(®ion.y1, ®ion.y2);
  178.     if(region.f1 > region.f2) swap(®ion.f1, ®ion.f2);
  179. }
  180.  
  181. /**********************************************/
  182. void
  183. swap(s1, s2)
  184. int *s1, *s2;
  185. {
  186.     int t;
  187.  
  188.     t = *s1;
  189.     *s1 = *s2;
  190.     *s2 = t;
  191. }    
  192.  
  193. /**********************************************/
  194. void
  195. grow_frame()
  196. {
  197.     void save_mask_undo_2d();
  198.     void save_mask_undo_3d();
  199.     void collect_frame();
  200.     void go_grow_edges();
  201.  
  202.  
  203.     if(grow.extent == GROW_FRAME) save_mask_undo_2d(grow.swin);
  204.     else save_mask_undo_3d(segal.e_m);
  205.  
  206.     vprint"Collecting seed points ...\n");
  207.     collect_frame(grow.seed_pt_src);
  208.  
  209.     go_grow_edges();
  210. }
  211.  
  212. /**********************************************/
  213. void
  214. go_grow_edges()
  215. {
  216.     Notify_value grow_edges();
  217.  
  218.     vprint"Growing edges ...\n");
  219.     if(grow.interractive) {
  220.         grow.itimer.it_value.tv_sec = INTERVAL_SEC;
  221.         grow.itimer.it_interval.tv_sec = INTERVAL_SEC;
  222.         grow.itimer.it_value.tv_usec = INTERVAL_uSEC;
  223.         grow.itimer.it_interval.tv_usec = INTERVAL_uSEC;
  224.         notify_set_itimer_func(Mask_grow_pop_mask_grow->pop_mask_grow,
  225.             grow_edges, ITIMER_REAL, &grow.itimer, NULL);
  226.     }
  227.     else while(grow_edges() != NOTIFY_DONE);
  228. }
  229.  
  230. /**********************************************/
  231. void
  232. collect_frame(pt_src)
  233. int pt_src;
  234. {
  235. /* puts all the points from pt_src (Edit Mask or Pt List) on the stack */
  236.     void get_3d_coords();
  237.     void push();
  238.  
  239.     int buf_bit, x, y, x1, y1, f1;
  240.  
  241.     if(pt_src == SEED_EDIT) buf_bit = segal.e_m;
  242.     else if(pt_src == SEED_PTS) buf_bit = BUF_PTS;
  243.  
  244.     grow.stack_empty = TRUE;
  245.  
  246.     for(x = 0; x < win[grow.swin].img_c - 1; x++)
  247.     for(y = 0; y < win[grow.swin].img_r - 1; y++)
  248.         if(BIT_IS_ON(win[grow.swin].m_data[y][x], m[buf_bit].bit_key)) {
  249.             get_3d_coords(win[grow.swin].aspect, ASPECT_Z,
  250.                 x, y, win[grow.swin].f,
  251.                 &x1, &y1, &f1);
  252.             push(NUM_BRIDGE_DIRS - 1, x1, y1, f1);
  253.         }
  254.     vprint"Collection found %d points\n", stack[NUM_BRIDGE_DIRS - 1].num_pts);
  255. }
  256.  
  257. /**********************************************/
  258. void
  259. auto_set_grow_params(pt_src)
  260. int pt_src;
  261. {
  262. /* find mins and maxes */
  263.     void erase_thresh_bounds();
  264.     void draw_thresh_bounds();
  265.     void set_grow_params();
  266.  
  267.     int buf_bit, x, y, x1, y1, f1, g, pval, i;
  268.     LOGIC set_orig_vals, b_satisfied;
  269.  
  270.     set_watch_cursor();
  271.  
  272.     if(pt_src == SEED_EDIT) buf_bit = segal.e_m;
  273.     else if(pt_src == SEED_PTS) buf_bit = BUF_PTS;
  274.  
  275.     set_orig_vals = FALSE;
  276.  
  277.     for(x = 0; x < win[grow.swin].img_c - 1; x++)
  278.     for(y = 0; y < win[grow.swin].img_r - 1; y++)
  279.         if(BIT_IS_ON(win[grow.swin].m_data[y][x], m[buf_bit].bit_key)) {
  280.             /* set initial values */
  281.             get_3d_coords(win[grow.swin].aspect, ASPECT_Z,
  282.                 x, y, win[grow.swin].f,
  283.                 &x1, &y1, &f1);
  284.  
  285.             if(grow.apply_thresholds) {
  286.                 if(segal.color)
  287.                     pval = MONO(cbuf[RP][f1][y1][x1],
  288.                         cbuf[GP][f1][y1][x1],
  289.                         cbuf[BP][f1][y1][x1]);
  290.                 else pval = ibuf[f1][y1][x1];
  291.                 grow.threshold_min = grow.threshold_max = pval;
  292.             }
  293.  
  294.             if(grow.apply_gradient) {
  295.                 grow.gradient_min = grow.gradient_max
  296.                     = gradient(x1, y1, f1);
  297.             }
  298.  
  299.             if(grow.apply_bridge) {
  300.                 grow.bridge_max = NUM_BRIDGE_DIRS;
  301.                 grow.bridge_min = NUM_BRIDGE_DIRS;
  302.             }
  303.  
  304.             set_orig_vals = TRUE;
  305.             break;
  306.         }
  307.  
  308.     if(!set_orig_vals) {
  309.         unset_watch_cursor();
  310.         return; /* empty pt_src */
  311.     }
  312.  
  313.     for(x = 0; x < win[grow.swin].img_c - 1; x++)
  314.     for(y = 0; y < win[grow.swin].img_r - 1; y++)
  315.         if(BIT_IS_ON(win[grow.swin].m_data[y][x], m[buf_bit].bit_key)) {
  316.             get_3d_coords(win[grow.swin].aspect, ASPECT_Z,
  317.                 x, y, win[grow.swin].f,
  318.                 &x1, &y1, &f1);
  319.  
  320.             if(grow.apply_thresholds) {
  321.                 if(segal.color)
  322.                     pval = MONO(cbuf[RP][f1][y1][x1],
  323.                         cbuf[GP][f1][y1][x1],
  324.                         cbuf[BP][f1][y1][x1]);
  325.                 else pval = ibuf[f1][y1][x1];
  326.  
  327.                 if(pval < grow.threshold_min)
  328.                     grow.threshold_min = pval;
  329.                 if(pval > grow.threshold_max)
  330.                     grow.threshold_max = pval;
  331.             }
  332.  
  333.             if(grow.apply_gradient) {
  334.                 g = gradient(x1, y1, f1);
  335.                 if(g < grow.gradient_min) grow.gradient_min = g;
  336.                 if(g > grow.gradient_max) grow.gradient_max = g;
  337.             }
  338.  
  339.             if(grow.apply_bridge) {
  340.               b_satisfied = FALSE;
  341.               while(!b_satisfied) {
  342.                 For_all_directions
  343.                     if(bridge_strength(x1, y1, f1, i)
  344.                     >= grow.bridge_min) {
  345.                         b_satisfied = TRUE;
  346.                         break;
  347.                     }
  348.                 if(!b_satisfied) {
  349.                     if(grow.bridge_min > 1) {
  350.                         grow.bridge_min--;
  351.                     }
  352.                     else {
  353.                         grow.bridge_min = NUM_BRIDGE_DIRS;
  354.                         if(grow.bridge_dist > 1) {
  355.                             grow.bridge_dist--;
  356.                         }
  357.                         else {
  358.                             /* get outta here! */
  359.                             vprint"***ERROR***\n");
  360.                             b_satisfied = TRUE;
  361.                         }
  362.                     }
  363.                 }
  364.               }
  365.             }
  366.         }
  367.  
  368.     erase_thresh_bounds();
  369.     threshold.min = grow.threshold_min;
  370.     threshold.max = grow.threshold_max;
  371.     draw_thresh_bounds();
  372.     set_grow_params();
  373.  
  374.     unset_watch_cursor();
  375. }
  376.  
  377. /**********************************************/
  378. void
  379. set_grow_params()
  380. {
  381.     xv_set(Mask_grow_pop_mask_grow->set_threshold_min,
  382.         PANEL_VALUE, grow.threshold_min,
  383.         PANEL_INACTIVE, (grow.apply_thresholds == FALSE),
  384.         NULL);
  385.     xv_set(Mask_grow_pop_mask_grow->set_threshold_max,
  386.         PANEL_VALUE, grow.threshold_max,
  387.         PANEL_INACTIVE, (grow.apply_thresholds == FALSE),
  388.         NULL);
  389.     xv_set(Mask_grow_pop_mask_grow->set_gradient_radius,
  390.         PANEL_VALUE, grow.gradient_rad,
  391.         PANEL_INACTIVE, (grow.apply_gradient == FALSE),
  392.         NULL);
  393.     xv_set(Mask_grow_pop_mask_grow->set_gradient_max,
  394.         PANEL_VALUE, grow.gradient_max,
  395.         PANEL_INACTIVE, (grow.apply_gradient == FALSE),
  396.         NULL);
  397.     xv_set(Mask_grow_pop_mask_grow->set_gradient_min,
  398.         PANEL_VALUE, grow.gradient_min,
  399.         PANEL_INACTIVE, (grow.apply_gradient == FALSE),
  400.         NULL);
  401.     xv_set(Mask_grow_pop_mask_grow->set_bridge_distance,
  402.         PANEL_VALUE, grow.bridge_dist,
  403.         PANEL_INACTIVE, (grow.apply_bridge == FALSE),
  404.         NULL);
  405.     xv_set(Mask_grow_pop_mask_grow->set_bridge_max,
  406.         PANEL_VALUE, grow.bridge_max,
  407.         PANEL_INACTIVE, (grow.apply_bridge == FALSE),
  408.         NULL);
  409.     xv_set(Mask_grow_pop_mask_grow->set_bridge_min,
  410.         PANEL_VALUE, grow.bridge_min,
  411.         PANEL_INACTIVE, (grow.apply_bridge == FALSE),
  412.         NULL);
  413. }
  414.  
  415. /**********************************************/
  416. Notify_value
  417. grow_edges()
  418. {
  419. /* all points are in the Z aspect */
  420.     void done_growing_mask();
  421.     u_long standout();
  422.     int pop();
  423.     void push();
  424.     void get_3d_coords();
  425.     void paint_cell();
  426.     void paint_view_cells();
  427.     LOGIC bit_is_included();
  428.     LOGIC bit_is_excluded();
  429.     LOGIC grow_into();
  430.     LOGIC shrink_into();
  431.  
  432.     int i, j, s, x, y, f, x1, y1, f1;
  433.  
  434.     if(grow.stack_empty) {
  435.         if(grow.interractive) notify_set_itimer_func(
  436.             Mask_grow_pop_mask_grow->pop_mask_grow,
  437.             NOTIFY_FUNC_NULL, ITIMER_REAL, NULL, NULL);
  438.         done_growing_mask();
  439.         return NOTIFY_DONE;
  440.     }
  441.  
  442.     for(j = 0; j < grow.speed; j++) {
  443.         if(grow.stack_empty) {
  444.             if(!grow.interractive) {
  445.                 done_growing_mask();
  446.                 return NOTIFY_DONE;
  447.             }
  448.             else break;
  449.         }
  450.  
  451.         /* some points left ... */
  452.         s = pop(&x, &y, &f);
  453.         if(grow.disp_growth >= DISP_GROW) {
  454.             /* translate (x, y, f) from Z to grow.swin aspect */
  455.             get_3d_coords(ASPECT_Z, win[grow.swin].aspect, x, y, f,
  456.                 &x1, &y1, &f1);
  457.             if(f1 == win[grow.swin].f)
  458.                 paint_cell(grow.swin, x1, y1, standout(s));
  459.             if(grow.disp_growth == DISP_ALL)
  460.                 paint_view_cells(ASPECT_Z, x, y, f, standout(s));
  461.         }
  462.  
  463.         if(grow.direction == DIR_GROW) {
  464.             For_all_directions {
  465.                 x1 = x + dx[i];
  466.                 y1 = y + dy[i];
  467.                 f1 = f + df[i];
  468.  
  469.                 if(x1 <= region.x2
  470.                 && y1 <= region.y2
  471.                 && f1 <= region.f2
  472.                 && x1 >= region.x1
  473.                 && y1 >= region.y1
  474.                 && f1 >= region.f1
  475.                 && !bit_is_excluded(mbuf[f1][y1][x1])
  476.                 && grow_into(i, x1, y1, f1, &s)) {
  477.                     TURN_BIT_ON(mbuf[f1][y1][x1], m[segal.e_m].bit_key)
  478.                     push(s - 1, x1, y1, f1);
  479.                 }
  480.             }
  481.         }
  482.         else {
  483.             For_all_directions {
  484.                 x1 = x + dx[i];
  485.                 y1 = y + dy[i];
  486.                 f1 = f + df[i];
  487.  
  488.                 if(x1 <= region.x2
  489.                 && y1 <= region.y2
  490.                 && f1 <= region.f2
  491.                 && x1 >= region.x1
  492.                 && y1 >= region.y1
  493.                 && f1 >= region.f1
  494.                 && !bit_is_included(mbuf[f1][y1][x1])
  495.                 && shrink_into(i, x1, y1, f1, &s)) {
  496.                     TURN_BIT_OFF(mbuf[f1][y1][x1], m[segal.e_m].bit_key)
  497.                     push(s - 1, x1, y1, f1);
  498.                 }
  499.             }
  500.         }
  501.     }
  502. }
  503.  
  504. /**********************************************/
  505. int
  506. pop(x, y, f)
  507. int *x, *y, *f;
  508. {
  509. /* pops from the priority stacks ... 7 first, 0 last */
  510.     void decrease_stack_space();
  511.  
  512.     int i;
  513.  
  514.     for(i = NUM_BRIDGE_DIRS - 1; i >=0; i--)
  515.         if(stack[i].num_pts > 0) {
  516.             *x = (int) stack[i].pts[stack[i].num_pts - 1].x;
  517.             *y = (int) stack[i].pts[stack[i].num_pts - 1].y;
  518.             *f = (int) stack[i].pts[stack[i].num_pts - 1].f;
  519.             stack[i].num_pts--;
  520.  
  521.             if(stack[i].num_pts <
  522.             (stack[i].max_pts - stack[i].num_pts_per_alloc))
  523.                 decrease_stack_space(i);
  524.             return(i);
  525.         }
  526.     grow.stack_empty = TRUE;
  527.     /* CHANGE - should return UNDEFINED */
  528.     return(0);
  529. }
  530.  
  531. /**********************************************/
  532. void
  533. push(s, x, y, f)
  534. int s, x, y, f;
  535. {
  536.     LOGIC increased_stack_space();
  537.  
  538.     if(stack[s].num_pts >= stack[s].max_pts)
  539.         while(!increased_stack_space(s));
  540.  
  541.     stack[s].pts[stack[s].num_pts].x = (unsigned short) x;
  542.     stack[s].pts[stack[s].num_pts].y = (unsigned short) y;
  543.     stack[s].pts[stack[s].num_pts].f = (unsigned short) f;
  544.     stack[s].num_pts++;
  545.     grow.stack_empty = FALSE;
  546. }
  547.  
  548. /**********************************************/
  549. LOGIC
  550. increased_stack_space(s)
  551. int s;
  552. {
  553.     POINT_TYPE *ptr;
  554.  
  555.     if((ptr = (POINT_TYPE *) realloc(stack[s].pts,
  556.         (stack[s].max_pts + stack[s].num_pts_per_alloc)
  557.         * sizeof(POINT_TYPE))) == NULL) {
  558.         if(stack[s].num_pts_per_alloc < NUM_PTS_PER_ALLOC / 32) {
  559.             vprint"Ran out of memory for the stack ... throwing away half the points!!!\n");
  560.             stack[s].num_pts /= 2;
  561.             stack[s].num_pts_per_alloc = NUM_PTS_PER_ALLOC;
  562.             return(TRUE);
  563.         }
  564.         else {
  565.             vprint"... using smaller stack increment\n");
  566.             stack[s].num_pts_per_alloc /= 2;
  567.             return(FALSE);
  568.         }
  569.     }
  570.     else {
  571.         stack[s].pts = ptr;
  572.         stack[s].max_pts += stack[s].num_pts_per_alloc;
  573.         vprint"Reallocating stack[%d] space ... max_pts up %d to %d\n",
  574.             s, stack[s].num_pts_per_alloc, stack[s].max_pts);
  575.         return(TRUE);
  576.     }
  577. }
  578.  
  579. /**********************************************/
  580. void
  581. decrease_stack_space(s)
  582. int s;
  583. {
  584.     POINT_TYPE *ptr;
  585.  
  586.     if((ptr = (POINT_TYPE *) realloc(stack[s].pts, (stack[s].max_pts
  587.         - stack[s].num_pts_per_alloc) * sizeof(POINT_TYPE))) != NULL) {
  588.         stack[s].pts = ptr;
  589.         stack[s].max_pts -= stack[s].num_pts_per_alloc;
  590.         stack[s].num_pts_per_alloc = NUM_PTS_PER_ALLOC;
  591.         vprint"Reallocating stack[%d] space ... max_pts down %d to %d\n", s, stack[s].num_pts_per_alloc, stack[s].max_pts);
  592.     }
  593. }
  594.  
  595. /**********************************************/
  596. LOGIC
  597. flood_criteria_satisfied(x, y, f)
  598. int x, y, f;
  599. {
  600.     int gradient();
  601.  
  602.     int g, pval;
  603.  
  604.     g = gradient(x, y, f);
  605.     if(segal.color) pval = MONO(cbuf[RP][f][y][x], cbuf[GP][f][y][x],
  606.         cbuf[BP][f][y][x]);
  607.     else pval = ibuf[f][y][x];
  608.  
  609.     return(pval <= grow.threshold_max
  610.     && pval >= grow.threshold_min
  611.     && g <= grow.gradient_max
  612.     && g >= grow.gradient_min);
  613. }
  614.  
  615. /**********************************************/
  616. LOGIC
  617. grow_into(growth_dir, x, y, f, b)
  618. int growth_dir, x, y, f, *b;
  619. {
  620.     LOGIC flood_criteria_satisfied();
  621.     int bridge_strength();
  622.  
  623.     return(!BIT_IS_ON(mbuf[f][y][x], m[segal.e_m].bit_key)
  624.     && flood_criteria_satisfied(x, y, f)
  625.     && (*b = bridge_strength(x, y, f, growth_dir)) <= grow.bridge_max
  626.     && *b >= grow.bridge_min);
  627. }
  628.  
  629. /**********************************************/
  630. LOGIC
  631. shrink_into(growth_dir, x, y, f, b)
  632. int growth_dir, x, y, f, *b;
  633. {
  634.     LOGIC flood_criteria_satisfied();
  635.     int bridge_strength();
  636.  
  637.     return(BIT_IS_ON(mbuf[f][y][x], m[segal.e_m].bit_key)
  638.     && flood_criteria_satisfied(x, y, f, growth_dir)
  639.     && (*b = bridge_strength(x, y, f, growth_dir)) <= grow.bridge_max
  640.     && *b >= grow.bridge_min);
  641. }
  642.  
  643. /**********************************************/
  644. int
  645. gradient(x, y, f)
  646. int x, y, f;
  647. {
  648. /* The gradient is really the distance between the average color of the
  649.  * neighborhood of x,y,f and the color at x,y,f itself.
  650.  */
  651.     int num_neighbors, ans, ans_r, ans_g, ans_b;
  652.     int x0, y0, f0, x1, y1, f1;
  653.     int i, j, k;
  654.  
  655.     if(!grow.apply_gradient) return(grow.gradient_min);
  656.  
  657.     ans = ans_r = ans_g = ans_b = 0;
  658.  
  659.     x0 = x - grow.gradient_rad;
  660.     y0 = y - grow.gradient_rad;
  661.     f0 = f - grow.gradient_rad;
  662.     x1 = x + grow.gradient_rad;
  663.     y1 = y + grow.gradient_rad;
  664.     f1 = f + grow.gradient_rad;
  665.  
  666.     RANGE(x0, 0, (segal.c - 1))
  667.     RANGE(y0, 0, (segal.r - 1))
  668.     RANGE(f0, 0, (segal.f - 1))
  669.     RANGE(x1, 0, (segal.c - 1))
  670.     RANGE(y1, 0, (segal.r - 1))
  671.     RANGE(f1, 0, (segal.f - 1))
  672.  
  673.     num_neighbors = (f1 - f0) * (y1 - y0) * (x1 - x0);
  674.  
  675.     if(segal.color) {
  676.         for(i = x0; i <= x1; i++)
  677.         for(j = y0; j <= y1; j++)
  678.         for(k = f0; k <= f1; k++)
  679.             if(i != x && j != y && k != f) {
  680.                 ans_r += cbuf[RP][k][j][i];
  681.                 ans_g += cbuf[GP][k][j][i];
  682.                 ans_b += cbuf[BP][k][j][i];
  683.             }
  684.         ans_r = ans_r / num_neighbors;
  685.         ans_g = ans_g / num_neighbors;
  686.         ans_b = ans_b / num_neighbors;
  687.         return(DISTANCE(ans_r, ans_g, ans_b,
  688.             cbuf[RP][f][y][x], cbuf[GP][f][y][x],
  689.             cbuf[BP][f][y][x]));
  690.     }
  691.     else {
  692.         for(i = x0; i <= x1; i++)
  693.         for(j = y0; j <= y1; j++)
  694.         for(k = f0; k <= f1; k++)
  695.             if(i != x && j != y && k != f) {
  696.                 ans += ibuf[k][j][i];
  697.             }
  698.         ans = ans / num_neighbors;
  699.         return(abs(ans - ibuf[f][y][x]));
  700.     }
  701.  
  702. }
  703.  
  704. /**********************************************/
  705. int
  706. bridge_strength(x, y, f, growth_dir)
  707. int x, y, f, growth_dir;
  708. {
  709. /* Returns true only if there exists a set of adjacent pixels "grow.min_bridge"
  710.  * long for which the flooding criteria is satisfied (threshold, gradient)
  711.  */
  712.     LOGIC flood_criteria_satisfied();
  713.  
  714.     int *xoff, *yoff, *foff;
  715.     int i, j, x1, y1, f1;
  716.     int last_connected, num_connections;
  717.  
  718.     if(!grow.apply_bridge) return grow.bridge_min;
  719.  
  720.     for(i = 0; i < NUM_BRIDGE_DIRS; i++)
  721.         connected[i] = TRUE;
  722.  
  723.     switch(growth_dir) {
  724.     case DIR_N :
  725.     case DIR_S :
  726.         xoff = xoff_ns;
  727.         yoff = yoff_ns;
  728.         foff = foff_ns;
  729.         break;
  730.     case DIR_E :
  731.     case DIR_W :
  732.         xoff = xoff_ew;
  733.         yoff = yoff_ew;
  734.         foff = foff_ew;
  735.         break;
  736.     case DIR_U :
  737.     case DIR_D :
  738.         xoff = xoff_ud;
  739.         yoff = yoff_ud;
  740.         foff = foff_ud;
  741.         break;
  742.     default :
  743.         break;
  744.     }
  745.  
  746.     for(i = 1; i <= grow.bridge_dist; i++)
  747.     for(j = 0; j < NUM_BRIDGE_DIRS; j++) { 
  748.         x1 = x + (xoff[j] * i);
  749.         y1 = y + (yoff[j] * i);
  750.         f1 = f + (foff[j] * i);
  751.  
  752.         /* if we`re not done yet and have gone out of bounds */
  753.         if(x1 > segal.c - 1
  754.         || y1 > segal.r - 1
  755.         || f1 > segal.f - 1
  756.         || x1 < 0
  757.         || y1 < 0
  758.         || f1 < 0)
  759.             connected[j] = FALSE;
  760.  
  761.         /* if we are in bounds but at a non-candidate pixel */
  762.         if(connected[j]
  763.         && !flood_criteria_satisfied(x1, y1, f1))
  764.             connected[j] = FALSE;
  765.     }
  766.  
  767.     /* see how many adjacent connections there are */
  768.     last_connected = NUM_BRIDGE_DIRS;
  769.     num_connections = 0;
  770.  
  771.     for(i = 0; i < NUM_BRIDGE_DIRS; i++)
  772.         if(connected[i]) num_connections++;
  773.         else if(num_connections > 0) {
  774.             last_connected = i - 1;
  775.             break;
  776.         }
  777.  
  778.     if(connected[0] && connected[NUM_BRIDGE_DIRS - 1])
  779.     /* then check from the other direction ... they're adjacent */
  780.     for(i = NUM_BRIDGE_DIRS - 1; i > last_connected; i--)
  781.         if(connected[i]) num_connections++;
  782.         else break;
  783.  
  784.  
  785.     return num_connections;
  786. }
  787.